/******************************************************************************
 * Product: Adempiere ERP & CRM Smart Business Solution                       *
 * Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved.                *
 * This program is free software; you can redistribute it and/or modify it    *
 * under the terms version 2 of the GNU General Public License as published   *
 * by the Free Software Foundation. This program is distributed in the hope   *
 * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied *
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.           *
 * See the GNU General Public License for more details.                       *
 * You should have received a copy of the GNU General Public License along    *
 * with this program; if not, write to the Free Software Foundation, Inc.,    *
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.                     *
 * For the text or an alternative of this public license, you may reach us    *
 * ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA        *
 * or via info@compiere.org or http://www.compiere.org/license.html           *
 *****************************************************************************/
package org.compiere.acct;

import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.logging.Level;

import org.compiere.model.MAccount;
import org.compiere.model.MAcctSchema;
import org.compiere.model.MConversionRate;
import org.compiere.model.MCostDetail;
import org.compiere.model.MFactAcct;
import org.compiere.model.MInvoiceLine;
import org.compiere.model.MLandedCostAllocation;
import org.compiere.model.MTable;
import org.compiere.model.Mhrmcharge;
import org.compiere.model.Mhrmpayment;
import org.compiere.model.Mhrmreserve;
import org.compiere.model.Mhrmvacation;
import org.compiere.model.Mhrmvacationline;
import org.compiere.model.ProductCost;
import org.compiere.model.X_hrm_charge;
import org.compiere.model.X_hrm_vacationline;
import org.compiere.util.DB;
import org.compiere.util.Env;

import extend.org.compiere.hrm.Reserve;
import extend.org.compiere.hrm.TaxCompute;
import extend.org.compiere.hrm.TaxVariable;
import extend.org.compiere.hrm.TypePayment;

/**
 *  Post HRM Vacation Documents.
 *  <pre>
 *  Table:              hrm_vacation (318)
 *  </pre>
 *  @author Sokolov V., Ibrayev E., A.Yerzhanov
 *  
 *  @version  $Id: hrm_vacation.java,v 1.0 2012/12/28 
 */
public class Doc_hrmvacation extends Doc
{
	/**
	 *  Constructor
	 * 	@param ass accounting schemata
	 * 	@param rs record
	 * 	@param trxName trx
	 */
	public Doc_hrmvacation(MAcctSchema[] ass, ResultSet rs, String trxName)
	{
		super (ass, Mhrmvacation.class, rs, null, trxName);
	}	//	Doc_hrmvacation

	/** Contained Optional Tax Lines    */
	private DocTax[]        m_taxes = null;

	/**
	 *  Load Specific Document Details
	 *  @return error message or null
	 */
	protected String loadDocumentDetails ()
	{
		
		Mhrmvacation hr = (Mhrmvacation)getPO();
		setDateDoc(hr.getDateAcct());
		p_lines = loadLines(hr);
		return null;
	}   //  loadDocumentDetails
	
	private DocLine[] loadLines (Mhrmvacation invoice)
	{
		ArrayList<DocLine> list = new ArrayList<DocLine>();
		DocLine[] dls = new DocLine[list.size()];
		list.toArray(dls);
		
		return dls;
	}


	/**************************************************************************
	 *  Get Source Currency Balance - subtracts line and tax amounts from total - no rounding
	 *  @return positive amount, if total invoice is bigger than lines
	 */
	public BigDecimal getBalance()
	{
		BigDecimal retValue = Env.ZERO;
		return retValue;
	}   //  getBalance

	/**
	 *  Create Facts (the accounting logic) for
	 *  ARI, ARC, ARF, API, APC.
	 *  <pre>
	 *  ARI, ARF
	 *      Receivables     DR
	 *      Charge                  CR
	 *      TaxDue                  CR
	 *      Revenue                 CR
	 *
	 *  ARC
	 *      Receivables             CR
	 *      Charge          DR
	 *      TaxDue          DR
	 *      Revenue         RR
	 *
	 *  API
	 *      Payables                CR
	 *      Charge          DR
	 *      TaxCredit       DR
	 *      Expense         DR
	 *
	 *  APC
	 *      Payables        DR
	 *      Charge                  CR
	 *      TaxCredit               CR
	 *      Expense                 CR
	 *  </pre>
	 *  @param as accounting schema
	 *  @return Fact
	 */
	public ArrayList<Fact> createFacts (MAcctSchema as)
	{
		//
		ArrayList<Fact> facts = new ArrayList<Fact>();
		
		
		//  create Fact Header
		
		//MAccount acct = null;
		MAccount acct7210 = getAccount(Doc.ACCTTYPE_HRMBankInTransit, as); //7210
		MAccount acct3120 = getAccount(Doc.ACCTTYPE_HRMIPN, as);	//3120
		MAccount acct3150 = getAccount(Doc.ACCTTYPE_HRMCNALOG, as);	//3150
		MAccount acct3210 = getAccount(Doc.ACCTTYPE_HRMCOTCH, as);	//3210
		MAccount acct3220 = getAccount(Doc.ACCTTYPE_HRMOPV, as);	//3220
		MAccount acct3350 = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
		MAccount acct3430 = getAccount(Doc.ACCTTYPE_HRMREZERV, as); //3430		
				
		Fact fact = new Fact(this, as, Fact.POST_Actual);
		Mhrmvacation vac = new Mhrmvacation(getCtx(), get_ID(), getTrxName());
		
		if (vac.haveCorrectDocument()) {
			facts = makeCorrectFact(vac, as);
			return facts;
		}
		
		
		Mhrmvacationline[] lines = vac.getLinesVacation();
		
		FactLine fl = null;	    		
    	setDateAcct(vac.getDateFrom());
		DocLine DocLine = null;
		X_hrm_vacationline charge = null;
		int C_Charge_ID = 0;
		
		/** Declare tax variable */
		TaxVariable taxValue = new TaxVariable(vac.getDateFrom()); 
		double taxMZP = taxValue.getMZP();		
		
		for(int i = 0; i < lines.length; i++ ){
			
			Mhrmvacationline line = lines[i];
			Integer bp =  line.getC_BPartner_ID();

			BigDecimal amountCharge = line.gethrm_total();
			BigDecimal amountCNalog = line.gethrm_CNalog();
			BigDecimal amountCOtch = line.gethrm_COtch();
			BigDecimal amountIPN = line.gethrm_IPN();
			BigDecimal amountOPV = line.gethrm_OPV();
			BigDecimal amountMaterialaid = line.gethrm_materialaid();
			
			Reserve reserve = new Reserve(bp, vac.getDateFrom(),Mhrmreserve.RESERVE_VACATION, acct3430.getAccount_ID());			
			BigDecimal reserveCharge = reserve.getSectional(Mhrmreserve.RESERVE_SECTIONAL_CHARGE);
			BigDecimal reserveCNalog = reserve.getSectional(Mhrmreserve.RESERVE_SECTIONAL_CNALOG);
			BigDecimal reserveCOtch = reserve.getSectional(Mhrmreserve.RESERVE_SECTIONAL_COTCH);
						
			BigDecimal diff = new BigDecimal(0);
			BigDecimal diffaid = new BigDecimal(0);						
						
    		// 1. Начисления            
			diff = reserveCharge.add(amountCharge.negate()); //.add(reserveCOtch.negate()).add(reserveCNalog.negate());			
			
	    	if (diff.signum() == -1) { // Если не хвтает на резерве, то занимаем у организации
	    		
	    	   	if (reserveCharge.compareTo(new BigDecimal(0)) == 1) { 
	    	   		setC_BPartner_ID(bp);
	    	   		//acct = getAccount(Doc.ACCTTYPE_HRMREZERV, as);	//3430
	    	   		fl = fact.createLine(null, acct3430, getC_Currency_ID(), reserveCharge, null);
	    	   		fl.setLine_ID(vac.getVacationLine(Mhrmreserve.RESERVE_SECTIONAL_CHARGE).gethrm_vacationline_ID());
	
	    	   		setC_BPartner_ID(bp);
	    	   		//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
	    	   		fl = fact.createLine(null, acct3350, getC_Currency_ID(), null, reserveCharge);
	    	    } 	    	 
		    	
	    	 // detect c_charge_id and fill hrm_paymentline
				C_Charge_ID = Mhrmcharge.getChargeID(X_hrm_charge.HRM_CHARGETYPE_Payment, vac.getDateFrom());
				charge = Mhrmvacationline.getline(vac.gethrm_vacation_ID(), bp, C_Charge_ID);
				if (charge == null || charge.get_ID() == 0){
					charge = new X_hrm_vacationline(getCtx(), 0, null);
				}
		    	charge.sethrm_vacation_ID(vac.gethrm_vacation_ID());
		    	charge.sethrm_vacation_line_ID(line.gethrm_vacation_line_ID());
		    	charge.setC_BPartner_ID(bp);
		    	charge.setC_Charge_ID(C_Charge_ID);
		    	charge.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
		    	charge.sethrm_amount(diff.negate());
		    	charge.sethrm_reserve_ID(0);
		    	charge.sethrm_reservesectional_ID(0);
		    	charge.saveEx();
		    	DocLine = new DocLine(charge, this);
		    	
				setC_BPartner_ID(bp);				
				fl = fact.createLine(DocLine, acct7210, getC_Currency_ID(), diff.negate(), null);
					
				setC_BPartner_ID(bp);				
				fl = fact.createLine(DocLine, acct3350, getC_Currency_ID(), null, diff.negate());
				
    		} else { // Списываем полную сумму
    	
    	   		setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMREZERV, as);	//3430
				fl = fact.createLine(null, acct3430, getC_Currency_ID(), amountCharge, null);
				fl.setLine_ID(vac.getVacationLine(Mhrmreserve.RESERVE_SECTIONAL_CHARGE).gethrm_vacationline_ID());
	
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
				fl = fact.createLine(null, acct3350, getC_Currency_ID(), null, amountCharge);
    		}
	    	
	    	// 2. Мат. помощь
	    	if (amountMaterialaid != null && amountMaterialaid.signum() == 1) { // Если есть начисляем
	    		TaxVariable taxMaterialaid = TaxCompute.getTypeTax(bp, vac.getDateFrom(), TypePayment.VACATIONAID); 

	    		BigDecimal materialaidIPN = new BigDecimal(taxMaterialaid.getIPN());
	    		BigDecimal materialaidOPV = new BigDecimal(taxMaterialaid.getOPV());     	
	    	
//			if (diff.signum() == -1){ // Если не хвтает на резерве, то занимаем у организации 
//	    		
//	    		setC_BPartner_ID(bp);
//				//acct = getAccount(Doc.ACCTTYPE_HRMBankInTransit, as);	//7210
//				fl = fact.createLine(null, acct7210, getC_Currency_ID(), amountMaterialaid, null);
//					
//				setC_BPartner_ID(bp);
//				//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
//				fl = fact.createLine(null, acct3350, getC_Currency_ID(), null, amountMaterialaid);
//				
//    		}else{ 
//    			    			
//    			diffaid = diff.add(amountMaterialaid.negate());
//    			
//    			if (diffaid.signum() == -1){    				
//    			
//    				if (diff.compareTo(new BigDecimal(0)) == 1) {    				
//    				
//		    			setC_BPartner_ID(bp);
//		    	   		//acct = getAccount(Doc.ACCTTYPE_HRMREZERV, as);	//3430
//		    	   		fl = fact.createLine(null, acct3430, getC_Currency_ID(), diff, null);
//		    	   		fl.setLine_ID(vac.getVacationLine(Mhrmreserve.RESERVE_SECTIONAL_CHARGE).gethrm_vacationline_ID());
//		
//		    	   		setC_BPartner_ID(bp);
//		    	   		//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
//		    	   		fl = fact.createLine(null, acct3350, getC_Currency_ID(), null, diff);
//		    	    }
    				
//    				setC_BPartner_ID(bp);
//    				//acct = getAccount(Doc.ACCTTYPE_HRMBankInTransit, as);	//7210
//    				fl = fact.createLine(null, acct7210, getC_Currency_ID(), diffaid.negate(), null);
//    					
//    				setC_BPartner_ID(bp);
//    				//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
//    				fl = fact.createLine(null, acct3350, getC_Currency_ID(), null, diffaid.negate());
//    			
//    			}else{  				
//    				    		
//	    			setC_BPartner_ID(bp);
//					//acct = getAccount(Doc.ACCTTYPE_HRMREZERV, as);	//3430
//					fl = fact.createLine(null, acct3430, getC_Currency_ID(), amountMaterialaid, null);
//					fl.setLine_ID(vac.getVacationLine(Mhrmreserve.RESERVE_SECTIONAL_CHARGE).gethrm_vacationline_ID());
//		
//					setC_BPartner_ID(bp);
//					//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
//					fl = fact.createLine(null, acct3350, getC_Currency_ID(), null, amountMaterialaid);					
//    			}
//	    	}
//    			
	    		/// IPN
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
				fl = fact.createLine(null, acct3350, getC_Currency_ID(), materialaidIPN, null);
					
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMIPN, as);	//3120
				fl = fact.createLine(null, acct3120, getC_Currency_ID(), null, materialaidIPN);
				
				/// OPV
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
				fl = fact.createLine(null, acct3350, getC_Currency_ID(), materialaidOPV, null);
					
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMOPV, as);	//3220
				fl = fact.createLine(null, acct3220, getC_Currency_ID(), null, materialaidOPV);	
	    		
	    		// detect c_charge_id and fill hrm_paymentline
				C_Charge_ID = Mhrmcharge.getChargeID(X_hrm_charge.HRM_CHARGETYPE_Aid, vac.getDateFrom());
				charge = Mhrmvacationline.getline(vac.gethrm_vacation_ID(), bp, C_Charge_ID);
				if (charge == null || charge.get_ID() == 0){
					charge = new X_hrm_vacationline(getCtx(), 0, null);
				}
		    	charge.sethrm_vacation_ID(vac.gethrm_vacation_ID());
		    	charge.sethrm_vacation_line_ID(line.gethrm_vacation_line_ID());
		    	charge.setC_BPartner_ID(bp);
		    	charge.setC_Charge_ID(C_Charge_ID);
		    	charge.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
		    	charge.sethrm_amount(amountMaterialaid);
		    	charge.sethrm_reserve_ID(0);
		    	charge.sethrm_reservesectional_ID(0);
		    	charge.saveEx();
		    	DocLine = new DocLine(charge, this);
		    	
	    		setC_BPartner_ID(bp);
	    		//acct = getAccount(Doc.ACCTTYPE_HRMBankInTransit, as);	//7210
				fl = fact.createLine(DocLine, acct7210, getC_Currency_ID(), amountMaterialaid, null);
	
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
				fl = fact.createLine(DocLine, acct3350, getC_Currency_ID(), null, amountMaterialaid); 	

	    	}
	    	
	    	// В начале снимаем ИПН и пенсионные
	    	
			/// IPN
			setC_BPartner_ID(bp);
			//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
			fl = fact.createLine(null, acct3350, getC_Currency_ID(), amountIPN, null);
				
			setC_BPartner_ID(bp);
			//acct = getAccount(Doc.ACCTTYPE_HRMIPN, as);	//3120
			fl = fact.createLine(null, acct3120, getC_Currency_ID(), null, amountIPN);
			
			/// OPV
			setC_BPartner_ID(bp);
			//acct = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
			fl = fact.createLine(null, acct3350, getC_Currency_ID(), amountOPV, null);
				
			setC_BPartner_ID(bp);
			//acct = getAccount(Doc.ACCTTYPE_HRMOPV, as);	//3220
			fl = fact.createLine(null, acct3220, getC_Currency_ID(), null, amountOPV);
			
	    	// 2. Соц. налог  
	    	diff = reserveCNalog.add(amountCNalog.negate());    	
	    		
	    	if (diff.signum() == -1) { // Если не хвтает на резерве, то занимаем у организации

	    		if (reserveCNalog.compareTo(new BigDecimal(0)) == 1) { 
	    			
	    			setC_BPartner_ID(bp);
					//acct = getAccount(Doc.ACCTTYPE_HRMREZERV, as);	//3430
					fl = fact.createLine(null, acct3430, getC_Currency_ID(), reserveCNalog, null);
					fl.setLine_ID(vac.getVacationLine(Mhrmreserve.RESERVE_SECTIONAL_CNALOG).gethrm_vacationline_ID());
	
					setC_BPartner_ID(bp);
					//acct = getAccount(Doc.ACCTTYPE_HRMCNALOG, as);	//3150
					fl = fact.createLine(null, acct3150, getC_Currency_ID(), null, reserveCNalog);
	    	   	} 
				
	    		// detect c_charge_id and fill hrm_paymentline
				C_Charge_ID = Mhrmcharge.getChargeID(X_hrm_charge.HRM_CHARGETYPE_CNalog, vac.getDateFrom());
				charge = Mhrmvacationline.getline(vac.gethrm_vacation_ID(), bp, C_Charge_ID);
				if (charge == null || charge.get_ID() == 0){
					charge = new X_hrm_vacationline(getCtx(), 0, null);
				}
		    	charge.sethrm_vacation_ID(vac.gethrm_vacation_ID());
		    	charge.sethrm_vacation_line_ID(line.gethrm_vacation_line_ID());
		    	charge.setC_BPartner_ID(bp);
		    	charge.setC_Charge_ID(C_Charge_ID);
		    	charge.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
		    	charge.sethrm_amount(diff.negate());
		    	charge.sethrm_reserve_ID(0);
		    	charge.sethrm_reservesectional_ID(0);
		    	charge.saveEx();
		    	DocLine = new DocLine(charge, this);
		    	
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMBankInTransit, as);	//7210
				fl = fact.createLine(DocLine, acct7210, getC_Currency_ID(), diff.negate(), null);
					
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMCNALOG, as);	//3150
				fl = fact.createLine(DocLine, acct3150, getC_Currency_ID(), null, diff.negate());
					
	    	} else { // Списываем полную сумму
	    		
		    	setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMREZERV, as);	//3430
				fl = fact.createLine(null, acct3430, getC_Currency_ID(), amountCNalog, null);
				fl.setLine_ID(vac.getVacationLine(Mhrmreserve.RESERVE_SECTIONAL_CNALOG).gethrm_vacationline_ID());
	
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMCNALOG, as);	//3150
				fl = fact.createLine(null, acct3150, getC_Currency_ID(), null, amountCNalog);
	    	}
	    	
	    	// 2. Соц. налог 
	    	// 2. Мат. помощь
	    	if (amountMaterialaid != null && amountMaterialaid.signum() == 1) { // Если есть начисляем
	    		
	    		TaxVariable taxMaterialaid = TaxCompute.getTypeTax(bp, vac.getDateFrom(), TypePayment.VACATIONAID);
	    		BigDecimal materialaidCNalog = new BigDecimal(taxMaterialaid.getCNALOG());
	    		
//		    	if (diff.signum() == -1){  // Если не хвтает на резерве, то занимаем у организации 
		    		
	    		// detect c_charge_id and fill hrm_paymentline
				C_Charge_ID = Mhrmcharge.getChargeID(X_hrm_charge.HRM_CHARGETYPE_CNalog, vac.getDateFrom());
				charge = Mhrmvacationline.getline(vac.gethrm_vacation_ID(), bp, C_Charge_ID);
				if (charge == null || charge.get_ID() == 0){
					charge = new X_hrm_vacationline(getCtx(), 0, null);
				}
		    	charge.sethrm_vacation_ID(vac.gethrm_vacation_ID());
		    	charge.sethrm_vacation_line_ID(line.gethrm_vacation_line_ID());
		    	charge.setC_BPartner_ID(bp);
		    	charge.setC_Charge_ID(C_Charge_ID);
		    	charge.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
		    	charge.sethrm_amount(materialaidCNalog);
		    	charge.sethrm_reserve_ID(0);
		    	charge.sethrm_reservesectional_ID(0);
		    	charge.saveEx();
		    	DocLine = new DocLine(charge, this);
		    	
		    	setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMBankInTransit, as);	//7210
				fl = fact.createLine(DocLine, acct7210, getC_Currency_ID(), materialaidCNalog, null);
						
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMCNALOG, as);	//3150
				fl = fact.createLine(DocLine, acct3150, getC_Currency_ID(), null, materialaidCNalog);
		    		
//		    	}else{	    			    
//		    	 
//		    		diffaid = diff.add(materialaidCNalog.negate());
//		    		
//		    		if (diffaid.signum() == -1) { // Если не хвтает на резерве, то занимаем у организации
//	
//			    		if (diff.compareTo(new BigDecimal(0)) == 1) {
//			    			
//			    			setC_BPartner_ID(bp);
//							//acct = getAccount(Doc.ACCTTYPE_HRMREZERV, as);	//3430
//							fl = fact.createLine(null, acct3430, getC_Currency_ID(), diff, null);
//							fl.setLine_ID(vac.getVacationLine(Mhrmreserve.RESERVE_SECTIONAL_CNALOG).gethrm_vacationline_ID());
//			
//							setC_BPartner_ID(bp);
//							//acct = getAccount(Doc.ACCTTYPE_HRMCNALOG, as);	//3150
//							fl = fact.createLine(null, acct3150, getC_Currency_ID(), null, diff);
//			    	   	} 
						
//					setC_BPartner_ID(bp);
//					//acct = getAccount(Doc.ACCTTYPE_HRMBankInTransit, as);	//7210
//					fl = fact.createLine(null, acct7210, getC_Currency_ID(), diffaid.negate(), null);
//						
//					setC_BPartner_ID(bp);
//					//acct = getAccount(Doc.ACCTTYPE_HRMCNALOG, as);	//3150
//					fl = fact.createLine(null, acct3150, getC_Currency_ID(), null, diffaid.negate());
//						
//		    		}else{ // Списываем полную сумму
//		    		
//			    	setC_BPartner_ID(bp);
//					//acct = getAccount(Doc.ACCTTYPE_HRMREZERV, as);	//3430
//					fl = fact.createLine(null, acct3430, getC_Currency_ID(), materialaidCNalog, null);
//					fl.setLine_ID(vac.getVacationLine(Mhrmreserve.RESERVE_SECTIONAL_CNALOG).gethrm_vacationline_ID());
//		
//					setC_BPartner_ID(bp);
//					//acct = getAccount(Doc.ACCTTYPE_HRMCNALOG, as);	//3150
//					fl = fact.createLine(null, acct3150, getC_Currency_ID(), null, materialaidCNalog);
//		    		}
//		    	}
	    	}
	    	// закрытие соцналога
	    	
	    	// 3. Соц. отчисление
	    	BigDecimal materialaidCOtch = new BigDecimal(0);	    	
	    	if (amountMaterialaid != null && amountMaterialaid.signum() == 1) { // Если есть начисляем
	    		TaxVariable taxMaterialaid = TaxCompute.getTypeTax(bp, vac.getDateFrom(), TypePayment.VACATIONAID);	    		
	    		materialaidCOtch = new BigDecimal(taxMaterialaid.getCOTCH());	    		
	    	}	  
			
	    	amountCOtch = amountCOtch.add(materialaidCOtch);			
	    	taxMZP = taxMZP * 0.5;
	    	if (amountCOtch.compareTo(new BigDecimal(taxMZP)) == 1)
	    		amountCOtch = new BigDecimal(taxMZP);    	
	    	
    		diff = reserveCOtch.add(amountCOtch.negate());	    		
    		if (diff.signum() == -1) { // Если не хвтает на резерве, то занимаем у организации
    			
    	    	if (reserveCOtch.compareTo(new BigDecimal(0)) == 1) { 
		    		setC_BPartner_ID(bp);
					//acct = getAccount(Doc.ACCTTYPE_HRMREZERV, as);	//3430
					fl = fact.createLine(null, acct3430, getC_Currency_ID(), reserveCOtch, null);
					fl.setLine_ID(vac.getVacationLine(Mhrmreserve.RESERVE_SECTIONAL_COTCH).gethrm_vacationline_ID());
	
					setC_BPartner_ID(bp);
					//acct = getAccount(Doc.ACCTTYPE_HRMCOTCH, as);	//3210
					fl = fact.createLine(null, acct3210, getC_Currency_ID(), null, reserveCOtch);
    	    	} 
				
    	    	// detect c_charge_id and fill hrm_paymentline
    			C_Charge_ID = Mhrmcharge.getChargeID(X_hrm_charge.HRM_CHARGETYPE_COtche, vac.getDateFrom());
    			charge = Mhrmvacationline.getline(vac.gethrm_vacation_ID(), bp, C_Charge_ID);
    			if (charge == null || charge.get_ID() == 0){
    				charge = new X_hrm_vacationline(getCtx(), 0, null);
    			}
    	    	charge.sethrm_vacation_ID(vac.gethrm_vacation_ID());
    	    	charge.sethrm_vacation_line_ID(line.gethrm_vacation_line_ID());
    	    	charge.setC_BPartner_ID(bp);
    	    	charge.setC_Charge_ID(C_Charge_ID);
    	    	charge.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
		    	charge.sethrm_amount(diff.negate());
		    	charge.sethrm_reserve_ID(0);
		    	charge.sethrm_reservesectional_ID(0);
    	    	charge.saveEx();
    	    	DocLine = new DocLine(charge, this);
    	    	
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMBankInTransit, as);	//7210
				fl = fact.createLine(DocLine, acct7210, getC_Currency_ID(), diff.negate(), null);
					
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMCOTCH, as);	//3210
				fl = fact.createLine(DocLine, acct3210, getC_Currency_ID(), null, diff.negate());
					
    		} else { // Списываем полную сумму
    			
	    		setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMREZERV, as);	//3430
				fl = fact.createLine(null, acct3430, getC_Currency_ID(), amountCOtch, null);
				fl.setLine_ID(vac.getVacationLine(Mhrmreserve.RESERVE_SECTIONAL_COTCH).gethrm_vacationline_ID());
	
				setC_BPartner_ID(bp);
				//acct = getAccount(Doc.ACCTTYPE_HRMCOTCH, as);	//3210
				fl = fact.createLine(null, acct3210, getC_Currency_ID(), null, amountCOtch);
    		}
		
//    		// 2. Мат. помощь
//	    	if (amountMaterialaid != null && amountMaterialaid.signum() == 1) { // Если есть начисляем
//	    		TaxVariable taxMaterialaid = TaxCompute.getTypeTax(bp, vac.getDateFrom(), TypePayment.VACATIONAID); 
//	    		
//	    		BigDecimal materialaidCOtch = new BigDecimal(taxMaterialaid.getCOTCH());
//	    	
//    		diffaid = diff.add(materialaidCOtch.negate());
//	    		
//    		if (diffaid.signum() == -1) { // Если не хвтает на резерве, то занимаем у организации
//    			
//    	    	if (diff.compareTo(new BigDecimal(0)) == 1) { 
//    	    		
//		    		setC_BPartner_ID(bp);
//					//acct = getAccount(Doc.ACCTTYPE_HRMREZERV, as);	//3430
//					fl = fact.createLine(null, acct3430, getC_Currency_ID(), diff, null);
//					fl.setLine_ID(vac.getVacationLine(Mhrmreserve.RESERVE_SECTIONAL_COTCH).gethrm_vacationline_ID());
//	
//					setC_BPartner_ID(bp);
//					//acct = getAccount(Doc.ACCTTYPE_HRMCOTCH, as);	//3210
//					fl = fact.createLine(null, acct3210, getC_Currency_ID(), null, diff);
//    	    	} 
//					
//				setC_BPartner_ID(bp);
//				//acct = getAccount(Doc.ACCTTYPE_HRMBankInTransit, as);	//7210
//				fl = fact.createLine(null, acct7210, getC_Currency_ID(), diffaid.negate(), null);
//					
//				setC_BPartner_ID(bp);
//				//acct = getAccount(Doc.ACCTTYPE_HRMCOTCH, as);	//3210
//				fl = fact.createLine(null, acct3210, getC_Currency_ID(), null, diffaid.negate());
//					
//    		} else { // Списываем полную сумму
//    			
//	    		setC_BPartner_ID(bp);
//				//acct = getAccount(Doc.ACCTTYPE_HRMREZERV, as);	//3430
//				fl = fact.createLine(null, acct3430, getC_Currency_ID(), materialaidCOtch, null);
//				fl.setLine_ID(vac.getVacationLine(Mhrmreserve.RESERVE_SECTIONAL_COTCH).gethrm_vacationline_ID());
//	
//				setC_BPartner_ID(bp);
//				//acct = getAccount(Doc.ACCTTYPE_HRMCOTCH, as);	//3210
//				fl = fact.createLine(null, acct3210, getC_Currency_ID(), null, materialaidCOtch);
//    		}
//		  }		
		}

		facts.add(fact);
		return facts;
	}   //  createFact
	
	/**
	 * @param vac
	 * @param as
	 * @return
	 */
	private ArrayList<Fact> makeCorrectFact(Mhrmvacation vac, MAcctSchema as) {
		ArrayList<Fact> facts = new ArrayList<Fact>();

		int Reversal_ID = vac.getReversal_ID();
		Mhrmvacation reversal = new Mhrmvacation(getCtx(),Reversal_ID,vac.get_TrxName());
		
		String sql = "SELECT * FROM hrm_vacation WHERE hrm_vacation_id = ?";
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try{
			pstmt = DB.prepareStatement(sql, null);
			pstmt.setInt(1, vac.gethrm_vacation_ID());
			rs = pstmt.executeQuery();
			if (rs != null) {
				MAcctSchema[] ass = as.getClientAcctSchema(getCtx(), Env.getAD_Client_ID(getCtx()));
				Doc_hrmvacation reversalDoc = (Doc_hrmvacation) Doc.get(ass, MTable.getTable_ID(reversal.get_TableName()), reversal.gethrm_vacation_ID(), getTrxName());
				
				String sql1 = "SELECT * FROM Fact_Acct \n"
						    + "WHERE AD_Org_ID = ? \n"
						    + "  AND AD_Client_ID = ? \n"
						    + "  AND AD_Table_ID = ? \n"
						    + "  AND Record_ID = ? \n "
						    + "  AND PostingType = ? \n";
				int temp_AD_Org_ID = reversalDoc.getAD_Org_ID();
				int temp_AD_Cleint_ID = reversalDoc.getAD_Client_ID();
				int temp_AD_Table_ID = MTable.getTable_ID(vac.get_TableName());
				int temp_Record_ID = Reversal_ID;
				String temp_PostingType = Fact.POST_Actual; 
				PreparedStatement pstmt1 = null;
				ResultSet rs1 = null;
				Fact fact = new Fact(this, as, Fact.POST_Actual);
				try {
					pstmt1 = DB.prepareStatement(sql1, vac.get_TrxName());
					pstmt1.setInt(1, temp_AD_Cleint_ID);
					pstmt1.setInt(2, temp_AD_Org_ID);
					pstmt1.setInt(3, temp_AD_Table_ID);
					pstmt1.setInt(4, temp_Record_ID);
					pstmt1.setString(5, temp_PostingType);
					rs1 = pstmt1.executeQuery();
					while(rs1.next()) {
						MFactAcct fa = new MFactAcct(Env.getCtx(),rs1,vac.get_TrxName());
						MAccount account = getAccount(fa,as); // TODO 
						FactLine fl = fact.createLine(null, account,fa.getC_Currency_ID(), fa.getAmtAcctDr().negate(), fa.getAmtAcctCr().negate());
					}
				} catch(SQLException e) {
					log.log(Level.WARNING, e.getLocalizedMessage());
				} finally {
					DB.close(rs1, pstmt1);
					rs1 =null;
					pstmt1 = null;
				}
				facts.add(fact);
			}
		} catch(SQLException e) {
			log.log(Level.WARNING, e.getLocalizedMessage());
		} finally {
			DB.close(rs, pstmt);
			rs =null;
			pstmt = null;
		}
		
		return facts;
	}

	private MAccount getAccount(MFactAcct fa,	MAcctSchema as) {
		//TODO Сделать под общий вариант!
		MAccount result = null;
		
		MAccount acct7210 = getAccount(Doc.ACCTTYPE_HRMBankInTransit, as); //7210
		MAccount acct3120 = getAccount(Doc.ACCTTYPE_HRMIPN, as);	//3120
		MAccount acct3150 = getAccount(Doc.ACCTTYPE_HRMCNALOG, as);	//3150
		MAccount acct3210 = getAccount(Doc.ACCTTYPE_HRMCOTCH, as);	//3210
		MAccount acct3220 = getAccount(Doc.ACCTTYPE_HRMOPV, as);	//3220
		MAccount acct3350 = getAccount(Doc.ACCTTYPE_HRMSalary, as);	//3350
		MAccount acct3430 = getAccount(Doc.ACCTTYPE_HRMREZERV, as); //3430
		if (acct7210.getAccount().getC_ElementValue_ID() == fa.getAccount_ID()) {
			result = acct7210; 
		} else if (acct3120.getAccount().getC_ElementValue_ID() == fa.getAccount_ID()) {
			result = acct3120; 
		} else if (acct3150.getAccount().getC_ElementValue_ID() == fa.getAccount_ID()) {
			result = acct3150; 
		} else if (acct3210.getAccount().getC_ElementValue_ID() == fa.getAccount_ID()) {
			result = acct3210; 
		} else if (acct3220.getAccount().getC_ElementValue_ID() == fa.getAccount_ID()) {
			result = acct3220; 
		} else if (acct3350.getAccount().getC_ElementValue_ID() == fa.getAccount_ID()) {
			result = acct3350; 
		} else if (acct3430.getAccount().getC_ElementValue_ID() == fa.getAccount_ID()) {
			result = acct3430; 
		}
		return result;
	}
	
	public int checkValidCombination(int account_ID, int C_BPartner_ID){
		
		String sql = " select c_validcombination_id from c_validcombination where account_id = " + account_ID + " and c_bpartner_id = " + C_BPartner_ID;
		
		int AccountValid = 0;
		
		PreparedStatement pstmt = null;
		ResultSet rs = null;

		try{
			pstmt = DB.prepareStatement(sql, null);
			rs = pstmt.executeQuery();
			while (rs.next()) {
				AccountValid = rs.getInt(1);
			}
		}catch(SQLException e){
			log.log(Level.WARNING, e.getLocalizedMessage());
		}
		
		return AccountValid;		
	}
		
	/**
	 * 	Create Fact Cash Based (i.e. only revenue/expense)
	 *	@param as accounting schema
	 *	@param fact fact to add lines to
	 *	@param multiplier source amount multiplier
	 *	@return accounted amount
	 */
	public BigDecimal createFactCash (MAcctSchema as, Fact fact, BigDecimal multiplier)
	{
		boolean creditMemo = getDocumentType().equals(DOCTYPE_ARCredit)
			|| getDocumentType().equals(DOCTYPE_APCredit);
		boolean payables = getDocumentType().equals(DOCTYPE_APInvoice)
			|| getDocumentType().equals(DOCTYPE_APCredit);
		BigDecimal acctAmt = Env.ZERO;
		FactLine fl = null;
		//	Revenue/Cost
		for (int i = 0; i < p_lines.length; i++)
		{
			DocLine line = p_lines[i];
			boolean landedCost = false;
			if  (payables)
				landedCost = landedCost(as, fact, line, false);
			if (landedCost && as.isExplicitCostAdjustment())
			{
				fact.createLine (line, line.getAccount(ProductCost.ACCTTYPE_P_Expense, as),
					getC_Currency_ID(), null, line.getAmtSource());
				//
				fl = fact.createLine (line, line.getAccount(ProductCost.ACCTTYPE_P_Expense, as),
					getC_Currency_ID(), line.getAmtSource(), null);
				String desc = line.getDescription();
				if (desc == null)
					desc = "100%";
				else
					desc += " 100%";
				fl.setDescription(desc);
			}
			if (!landedCost)
			{
				MAccount acct = line.getAccount(
					payables ? ProductCost.ACCTTYPE_P_Expense : ProductCost.ACCTTYPE_P_Revenue, as);
				if (payables)
				{
					//	if Fixed Asset
					if (line.isItem())
						acct = line.getAccount (ProductCost.ACCTTYPE_P_InventoryClearing, as);
				}
				BigDecimal amt = line.getAmtSource().multiply(multiplier);
				BigDecimal amt2 = null;
				if (creditMemo)
				{
					amt2 = amt;
					amt = null;
				}
				if (payables)	//	Vendor = DR
					fl = fact.createLine (line, acct,
						getC_Currency_ID(), amt, amt2);
				else			//	Customer = CR
					fl = fact.createLine (line, acct,
						getC_Currency_ID(), amt2, amt);
				if (fl != null)
					acctAmt = acctAmt.add(fl.getAcctBalance());
			}
		}
		//  Tax
		for (int i = 0; i < m_taxes.length; i++)
		{
			BigDecimal amt = m_taxes[i].getAmount();
			BigDecimal amt2 = null;
			if (creditMemo)
			{
				amt2 = amt;
				amt = null;
			}
			FactLine tl = null;
			if (payables)
				tl = fact.createLine (null, m_taxes[i].getAccount(m_taxes[i].getAPTaxType(), as),
					getC_Currency_ID(), amt, amt2);
			else
				tl = fact.createLine (null, m_taxes[i].getAccount(DocTax.ACCTTYPE_TaxDue, as),
					getC_Currency_ID(), amt2, amt);
			if (tl != null)
				tl.setC_Tax_ID(m_taxes[i].getC_Tax_ID());
		}
		//  Set Locations
		FactLine[] fLines = fact.getLines();
		for (int i = 0; i < fLines.length; i++)
		{
			if (fLines[i] != null)
			{
				if (payables)
				{
					fLines[i].setLocationFromBPartner(getC_BPartner_Location_ID(), true);  //  from Loc
					fLines[i].setLocationFromOrg(fLines[i].getAD_Org_ID(), false);    //  to Loc
				}
				else
				{
					fLines[i].setLocationFromOrg(fLines[i].getAD_Org_ID(), true);    //  from Loc
					fLines[i].setLocationFromBPartner(getC_BPartner_Location_ID(), false);  //  to Loc
				}
			}
		}
		return acctAmt;
	}	//	createFactCash
	
	
	/**
	 * 	Create Landed Cost accounting & Cost lines
	 *	@param as accounting schema
	 *	@param fact fact
	 *	@param line document line
	 *	@param dr DR entry (normal api)
	 *	@return true if landed costs were created
	 */
	private boolean landedCost (MAcctSchema as, Fact fact, DocLine line, boolean dr) 
	{
		int C_InvoiceLine_ID = line.get_ID();
		MLandedCostAllocation[] lcas = MLandedCostAllocation.getOfInvoiceLine(
			getCtx(), C_InvoiceLine_ID, getTrxName());
		if (lcas.length == 0)
			return false;
		
		//	Calculate Total Base
		double totalBase = 0;
		for (int i = 0; i < lcas.length; i++)
			totalBase += lcas[i].getBase().doubleValue();
		
		//	Create New
		MInvoiceLine il = new MInvoiceLine (getCtx(), C_InvoiceLine_ID, getTrxName());
		for (int i = 0; i < lcas.length; i++)
		{
			MLandedCostAllocation lca = lcas[i];
			if (lca.getBase().signum() == 0)
				continue;
			double percent = lca.getBase().doubleValue() / totalBase;
			String desc = il.getDescription();
			if (desc == null)
				desc = percent + "%";
			else
				desc += " - " + percent + "%";
			if (line.getDescription() != null)
				desc += " - " + line.getDescription(); 
			
			//	Accounting
			ProductCost pc = new ProductCost (Env.getCtx(), 
				lca.getM_Product_ID(), lca.getM_AttributeSetInstance_ID(), getTrxName());
			BigDecimal drAmt = null;
			BigDecimal crAmt = null;
			if (dr)
				drAmt = lca.getAmt();
			else
				crAmt = lca.getAmt();
			FactLine fl = fact.createLine (line, pc.getAccount(ProductCost.ACCTTYPE_P_CostAdjustment, as),
				getC_Currency_ID(), drAmt, crAmt);
			fl.setDescription(desc);
			fl.setM_Product_ID(lca.getM_Product_ID());
			
			//	Cost Detail - Convert to AcctCurrency
			BigDecimal allocationAmt =  lca.getAmt();
			if (getC_Currency_ID() != as.getC_Currency_ID())
				allocationAmt = MConversionRate.convert(getCtx(), allocationAmt, 
					getC_Currency_ID(), as.getC_Currency_ID(),
					getDateAcct(), getC_ConversionType_ID(), 
					getAD_Client_ID(), getAD_Org_ID());
			if (allocationAmt.scale() > as.getCostingPrecision())
				allocationAmt = allocationAmt.setScale(as.getCostingPrecision(), BigDecimal.ROUND_HALF_UP);
			if (!dr)
				allocationAmt = allocationAmt.negate();
			// AZ Goodwill
			// use createInvoice to create/update non Material Cost Detail
			MCostDetail.createInvoice(as, lca.getAD_Org_ID(), 
					lca.getM_Product_ID(), lca.getM_AttributeSetInstance_ID(),
					C_InvoiceLine_ID, lca.getM_CostElement_ID(),
					allocationAmt, lca.getQty(),
					desc, getTrxName());
			// end AZ
		}
		
		log.config("Created #" + lcas.length);
		return true;
	}	//	landedCosts
	
	@Override
	public int getC_Currency_ID() {
		int result = super.getC_Currency_ID();
		if (result <= 0) {
			int AD_Client_ID =  Env.getAD_Client_ID(getCtx());
		    MAcctSchema[] acctSchema = MAcctSchema.getClientAcctSchema(getCtx(), AD_Client_ID, getTrxName());
		    for(MAcctSchema as: acctSchema) {
		    	if (as.isActive()) { //TODO определить актуальную схему по клиенту!
		    		result = as.getC_Currency_ID();
		    	}
		    }
		}
		return result;
	}
}   //  Doc_HRM
